package charter

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"math/rand"
	"os"
	"time"

	"github.com/wcharczuk/go-chart"
	"github.com/wcharczuk/go-chart/drawing"
)

const (
	lineChartXAxisName  = "Date"
	lineChartYAxisName  = "Count"
	lineChartHeight     = 700
	lineChartWidth      = 1280
	colorMultiplier     = 256
	imgStrPrefix        = "data:image/png;base64,"
	pieLabelFormat      = "%v %v"
	barChartTryAgainErr = "invalid data range; cannot be zero"
)

var (
	lineChartStyle = chart.Style{
		Padding: chart.Box{
			Top:  30,
			Left: 150,
		},
	}

	defaultChartStyle = chart.Style{
		Padding: chart.Box{
			Top: 30,
		},
	}

	timeFormat = chart.TimeDateValueFormatter
)

type LineYValue struct {
	Name   string
	Values []float64
}

type ChartValue struct {
	Name  string
	Value float64
}

// createLineChart 创建线性图
func createLineChart(title string, endTime time.Time, values []LineYValue) (img string, err error) {
	if len(values) == 0 {
		return
	}
	// 1、计算X轴
	lenX := len(values[0].Values)
	// X轴内容xValues 及 X轴坐标ticks
	var xValues []time.Time
	var ticks []chart.Tick
	for i := lenX - 1; i >= 0; i-- {
		curTime := endTime.AddDate(0, 0, -i)
		xValues = append(xValues, curTime)
		ticks = append(ticks, chart.Tick{Value: getNsec(curTime), Label: timeFormat(curTime)})
	}

	// 2、生成Series
	var series []chart.Series
	for _, yValue := range values {
		series = append(series, chart.TimeSeries{
			Name: yValue.Name,
			Style: chart.Style{
				Show: true,
				// 随机渲染线条颜色
				StrokeColor: drawing.Color{
					R: uint8(rand.Intn(colorMultiplier)),
					G: uint8(rand.Intn(colorMultiplier)),
					B: uint8(rand.Intn(colorMultiplier)),
					A: uint8(colorMultiplier - 1), // 透明度
				},
			},
			XValues: xValues,
			YValues: yValue.Values,
		})
	}

	// 3、新建图形
	graph := chart.Chart{
		Title:      title,
		Background: lineChartStyle,
		Width:      lineChartWidth,
		Height:     lineChartHeight,
		XAxis: chart.XAxis{
			Name:           lineChartXAxisName,
			ValueFormatter: timeFormat,
			Ticks:          ticks,
		},
		YAxis: chart.YAxis{
			Name: lineChartYAxisName,
		},
		Series: series,
	}
	graph.Elements = []chart.Renderable{
		chart.LegendLeft(&graph),
	}

	// 4、输出目标
	img, err = writeLineChartToPng(&graph)

	return
}

// getNsec 获取纳秒数
func getNsec(cur time.Time) float64 {
	return float64(cur.Unix() * int64(time.Second))
}

func writeLineChartToPng(c *chart.Chart) (img string, err error) {
	f, _ := os.Create("graph.png")
	err = c.Render(chart.PNG, f)
	return
}

func writeLineChart(c *chart.Chart) (img string, err error) {
	var imgContent bytes.Buffer
	err = c.Render(chart.PNG, &imgContent)
	if err != nil {
		return
	}

	img = imgToStr(imgContent)
	return
}

func imgToStr(imgContent bytes.Buffer) string {
	return imgStrPrefix + base64.StdEncoding.EncodeToString(imgContent.Bytes())
}

// createPieChart 创建饼图
func createPieChart(title string, pieValues []ChartValue) (img string, err error) {
	if len(pieValues) == 0 {
		return
	}
	// 1、构建value
	var values []chart.Value
	for _, v := range pieValues {

		values = append(values, chart.Value{
			Value: v.Value,
			Label: fmt.Sprintf(pieLabelFormat, getSimpleSensType(v.Name), formatValue(v.Value)),
		})
	}

	// 2、新建饼图
	pie := chart.PieChart{
		Title:      title,
		Background: defaultChartStyle,
		Values:     values,
	}

	// 4、输出目标
	img, err = writePieChartToPng(&pie)

	return
}

func formatValue(f float64) string {
	return fmt.Sprintf("%.2fW", f/10000)
}

func getSimpleSensType(name string) string {
	if name == "个人数据" {
		return "Personal"
	}
	return "Other"
}

func writePieChartToPng(c *chart.PieChart) (img string, err error) {
	f, _ := os.Create("pie.png")
	err = c.Render(chart.PNG, f)
	return
}

func writePieChart(c *chart.PieChart) (img string, err error) {
	var imgContent bytes.Buffer
	err = c.Render(chart.PNG, &imgContent)
	if err != nil {
		return
	}

	img = imgToStr(imgContent)
	return
}

// createBarChart 创建柱状图
func createBarChart(title string, barValues []ChartValue) (img string, err error) {
	if len(barValues) == 0 {
		return
	}
	// 1、构建value
	var values []chart.Value
	for _, v := range barValues {
		values = append(values, chart.Value{
			Value: v.Value,
			Label: v.Name,
		})
	}

	// 2、新建柱状图
	bar := chart.BarChart{
		XAxis: chart.Style{
			Show:     true,
			TextWrap: 0, // default 1为可以溢出规定的范围
		},
		YAxis: chart.YAxis{
			Style: chart.Style{
				Show:     true,
				TextWrap: 0, // default 1为可以溢出规定的范围
			},
		},
		Width:      2560,
		BarWidth:   50,
		BarSpacing: 300,
		Title:      title,
		Background: defaultChartStyle,
		Bars:       values,
	}

	// 4、输出目标
	img, err = writeBarChart(&bar)
	//img, err = writeBarChartToPng(&bar)
	//异常处理
	if err != nil && err.Error() == barChartTryAgainErr {
		// 添加一个隐藏条目，设置透明度A为0, 设置任意属性如R不为0即可
		values = append(values, chart.Value{
			Style: chart.Style{
				StrokeColor: drawing.Color{R: 1},
			},
			Value: 0,
			Label: "",
		})
		bar.Bars = values
		img, err = writeBarChart(&bar)
	}

	return
}

func writeBarChartToPng(c *chart.BarChart) (img string, err error) {
	f, _ := os.Create("bar.png")
	err = c.Render(chart.PNG, f)
	return
}

// 生成base64编码格式, <img src="...">
func writeBarChart(c *chart.BarChart) (img string, err error) {
	var imgContent bytes.Buffer
	err = c.Render(chart.PNG, &imgContent)
	if err != nil {
		return
	}

	img = imgToStr(imgContent)
	return
}
